package com.gee.spring.boot.rpf.client;

import com.gee.spring.boot.rpf.common.constant.ClientConstant;
import com.gee.spring.boot.rpf.controller.fico.RequestWrapper;
import com.gee.spring.boot.rpf.entity.Client;
import com.gee.spring.boot.rpf.util.context.ApplicationContextUtil;
import com.gee.spring.boot.rpf.util.redis.RedisUtil;
import com.gee.thread.flow.common.exception.GlobalSkippedException;
import com.gee.thread.flow.executor.ExecuteContext;
import com.gee.thread.flow.work.AbstractWork;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * desc:
 *
 * @author gee wrote on  2021-02-03 10:35:57
 */
public abstract class AbstractClient<P,R> extends AbstractWork<RequestWrapper,P,R> {

    private final Logger logger = LoggerFactory.getLogger(AbstractClient.class);

    private String id;

    private Client clientMeta;

    @Override
    public R process(P req) throws Exception {
        String cacheKey = ClientConstant.CLIENT_CACHE_PRE_KEY + ":" + clientMeta.getClientCode()
                + ":" + getCacheKey(req);
        R r;
        try {
            r = getCache(cacheKey);
            if (r != null){
                logger.info("Client [{}] get result from cache, key: {}, result: {}", getId(), cacheKey, r);
                return r;
            }
            logger.info("Client [{}] call start, clientRequest: {}", getId(), req);
            r = call(req);
            logger.info("Client [{}] call end, Response: {}", getId(), r);
            Long cacheExpire = clientMeta.getCacheExpire();
            if (cacheExpire > 0){
                setCache(cacheKey, r, cacheExpire);
            }
        } catch (Exception e) {
            String message  = getId() + "  client execute exceptionally " + e.getMessage();
            logger.error(message, e);
            if (! clientMeta.getExecuteIfException()){
                throw new GlobalSkippedException(message);
            }else {
                throw e;
            }
        }
        return r;
    }

    /**
     * @param cacheKey  缓存key
     * @param r   接口结果
     * @param cacheExpire  缓存时间  单位:小时
     */
    private void setCache(String cacheKey, R r, Long cacheExpire) {
        RedisUtil redisUtil = ApplicationContextUtil.getBean(RedisUtil.class);
        redisUtil.set(cacheKey, r, cacheExpire * 60 * 60 * 1000);
    }

    @SuppressWarnings("unchecked")
    private R getCache(String cacheKey){
        return (R)ApplicationContextUtil.getBean(RedisUtil.class).get(cacheKey);
    };

    @Override
    public String getId(){
        return id;
    };

    public abstract String getCacheKey(P req);

    public abstract R call(P req) throws Exception;

    public void setId(String id) {
        this.id = id;
    }

    public void setClientMeta(Client clientMeta) {
        this.clientMeta = clientMeta;
    }

    @Override
    public void initExecuteContext(ExecuteContext<RequestWrapper> executeContext) {
        super.initExecuteContext(executeContext);
    }
}
